Name: Chidiebere Sam-Ogbonna¶

Stock and Revenue Data Visualization for Exxon Mobil Corporation (XOM) and Chevron Corporation (CVX)¶

Introduction:

This project provides a comprehensive overview of extracting and visualizing stock and revenue data for Exxon Mobil Corporation (XOM) and Chevron Corporation (CVX). The primary tasks include defining a graphing function, extracting stock data using yfinance, extracting revenue data using web scraping, and plotting the stock graphs for both companies. The interactive visualizations created provide valuable insights into the financial performance of these companies, aiding in better analysis and decision-making.

In [1]:
!pip install yfinance
!pip install pandas
!pip install requests
!pip install bs4
!pip install plotly
Collecting yfinance
  Downloading yfinance-0.2.40-py2.py3-none-any.whl.metadata (11 kB)
Collecting pandas>=1.3.0 (from yfinance)
  Downloading pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (19 kB)
Collecting numpy>=1.16.5 (from yfinance)
  Downloading numpy-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (60 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 60.9/60.9 kB 9.2 MB/s eta 0:00:00
Requirement already satisfied: requests>=2.31 in /opt/conda/lib/python3.11/site-packages (from yfinance) (2.31.0)
Collecting multitasking>=0.0.7 (from yfinance)
  Downloading multitasking-0.0.11-py3-none-any.whl.metadata (5.5 kB)
Collecting lxml>=4.9.1 (from yfinance)
  Downloading lxml-5.2.2-cp311-cp311-manylinux_2_28_x86_64.whl.metadata (3.4 kB)
Requirement already satisfied: platformdirs>=2.0.0 in /opt/conda/lib/python3.11/site-packages (from yfinance) (4.2.1)
Requirement already satisfied: pytz>=2022.5 in /opt/conda/lib/python3.11/site-packages (from yfinance) (2024.1)
Collecting frozendict>=2.3.4 (from yfinance)
  Downloading frozendict-2.4.4-py311-none-any.whl.metadata (23 kB)
Collecting peewee>=3.16.2 (from yfinance)
  Downloading peewee-3.17.5.tar.gz (3.0 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.0/3.0 MB 111.1 MB/s eta 0:00:00
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Requirement already satisfied: beautifulsoup4>=4.11.1 in /opt/conda/lib/python3.11/site-packages (from yfinance) (4.12.3)
Collecting html5lib>=1.1 (from yfinance)
  Downloading html5lib-1.1-py2.py3-none-any.whl.metadata (16 kB)
Requirement already satisfied: soupsieve>1.2 in /opt/conda/lib/python3.11/site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.5)
Requirement already satisfied: six>=1.9 in /opt/conda/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (1.16.0)
Requirement already satisfied: webencodings in /opt/conda/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (0.5.1)
Requirement already satisfied: python-dateutil>=2.8.2 in /opt/conda/lib/python3.11/site-packages (from pandas>=1.3.0->yfinance) (2.9.0)
Collecting tzdata>=2022.7 (from pandas>=1.3.0->yfinance)
  Downloading tzdata-2024.1-py2.py3-none-any.whl.metadata (1.4 kB)
Requirement already satisfied: charset-normalizer<4,>=2 in /opt/conda/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.3.2)
Requirement already satisfied: idna<4,>=2.5 in /opt/conda/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.7)
Requirement already satisfied: urllib3<3,>=1.21.1 in /opt/conda/lib/python3.11/site-packages (from requests>=2.31->yfinance) (2.2.1)
Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.11/site-packages (from requests>=2.31->yfinance) (2024.6.2)
Downloading yfinance-0.2.40-py2.py3-none-any.whl (73 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 73.5/73.5 kB 10.2 MB/s eta 0:00:00
Downloading frozendict-2.4.4-py311-none-any.whl (16 kB)
Downloading html5lib-1.1-py2.py3-none-any.whl (112 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 112.2/112.2 kB 17.4 MB/s eta 0:00:00
Downloading lxml-5.2.2-cp311-cp311-manylinux_2_28_x86_64.whl (5.0 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.0/5.0 MB 116.5 MB/s eta 0:00:0000:01
Downloading multitasking-0.0.11-py3-none-any.whl (8.5 kB)
Downloading numpy-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (19.3 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 19.3/19.3 MB 110.1 MB/s eta 0:00:0000:0100:01
Downloading pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (13.0 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 13.0/13.0 MB 120.5 MB/s eta 0:00:0000:010:01
Downloading tzdata-2024.1-py2.py3-none-any.whl (345 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 345.4/345.4 kB 40.2 MB/s eta 0:00:00
Building wheels for collected packages: peewee
  Building wheel for peewee (pyproject.toml) ... done
  Created wheel for peewee: filename=peewee-3.17.5-py3-none-any.whl size=138635 sha256=23041a5c6fe6427b156d1b607f236c77111a58fd887afd22dda5f790ef9a5fe2
  Stored in directory: /home/jupyterlab/.cache/pip/wheels/d2/cb/9c/c300d7bf782e07f1658c306743d5e30af7e4834001e4064a96
Successfully built peewee
Installing collected packages: peewee, multitasking, tzdata, numpy, lxml, html5lib, frozendict, pandas, yfinance
Successfully installed frozendict-2.4.4 html5lib-1.1 lxml-5.2.2 multitasking-0.0.11 numpy-2.0.0 pandas-2.2.2 peewee-3.17.5 tzdata-2024.1 yfinance-0.2.40
Requirement already satisfied: pandas in /opt/conda/lib/python3.11/site-packages (2.2.2)
Requirement already satisfied: numpy>=1.23.2 in /opt/conda/lib/python3.11/site-packages (from pandas) (2.0.0)
Requirement already satisfied: python-dateutil>=2.8.2 in /opt/conda/lib/python3.11/site-packages (from pandas) (2.9.0)
Requirement already satisfied: pytz>=2020.1 in /opt/conda/lib/python3.11/site-packages (from pandas) (2024.1)
Requirement already satisfied: tzdata>=2022.7 in /opt/conda/lib/python3.11/site-packages (from pandas) (2024.1)
Requirement already satisfied: six>=1.5 in /opt/conda/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas) (1.16.0)
Requirement already satisfied: requests in /opt/conda/lib/python3.11/site-packages (2.31.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /opt/conda/lib/python3.11/site-packages (from requests) (3.3.2)
Requirement already satisfied: idna<4,>=2.5 in /opt/conda/lib/python3.11/site-packages (from requests) (3.7)
Requirement already satisfied: urllib3<3,>=1.21.1 in /opt/conda/lib/python3.11/site-packages (from requests) (2.2.1)
Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.11/site-packages (from requests) (2024.6.2)
Collecting bs4
  Downloading bs4-0.0.2-py2.py3-none-any.whl.metadata (411 bytes)
Requirement already satisfied: beautifulsoup4 in /opt/conda/lib/python3.11/site-packages (from bs4) (4.12.3)
Requirement already satisfied: soupsieve>1.2 in /opt/conda/lib/python3.11/site-packages (from beautifulsoup4->bs4) (2.5)
Downloading bs4-0.0.2-py2.py3-none-any.whl (1.2 kB)
Installing collected packages: bs4
Successfully installed bs4-0.0.2
Requirement already satisfied: plotly in /opt/conda/lib/python3.11/site-packages (5.22.0)
Requirement already satisfied: tenacity>=6.2.0 in /opt/conda/lib/python3.11/site-packages (from plotly) (8.4.1)
Requirement already satisfied: packaging in /opt/conda/lib/python3.11/site-packages (from plotly) (24.0)
In [2]:
import yfinance as yf
import pandas as pd
import requests
from bs4 import BeautifulSoup
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from io import StringIO
In [3]:
def make_graph(stock_data, revenue_data, stock):
    fig = make_subplots(rows=2, cols=1, shared_xaxes=True, subplot_titles=("Historical Share Price", "Historical Revenue"), vertical_spacing=0.3)
    
    fig.add_trace(go.Scatter(x=pd.to_datetime(stock_data['Date']), y=stock_data['Close'].astype(float), name="Share Price"), row=1, col=1)
    
    fig.add_trace(go.Bar(x=revenue_data['Year'], y=revenue_data['Revenue'].astype(float), name="Revenue"), row=2, col=1)
    
    fig.update_xaxes(title_text="Date", row=1, col=1)
    fig.update_xaxes(title_text="Year", row=2, col=1)
    fig.update_yaxes(title_text="Price ($US)", row=1, col=1)
    fig.update_yaxes(title_text="Revenue ($US Millions)", row=2, col=1)
    
    fig.update_layout(
        showlegend=False,
        height=900,
        title=stock,
        xaxis_rangeslider_visible=True
    )
    
    fig.show()

Using yfinance to Extract Exxon Stock Data.

In [4]:
exxon = yf.Ticker("XOM")

exxon_data = exxon.history(period="max")

exxon_data.reset_index(inplace=True)
exxon_data.head()
Out[4]:
Date Open High Low Close Volume Dividends Stock Splits
0 1962-01-02 00:00:00-05:00 0.0 0.094836 0.094137 0.094137 902400 0.0 0.0
1 1962-01-03 00:00:00-05:00 0.0 0.095535 0.094137 0.095535 1200000 0.0 0.0
2 1962-01-04 00:00:00-05:00 0.0 0.096234 0.095302 0.095768 1088000 0.0 0.0
3 1962-01-05 00:00:00-05:00 0.0 0.096234 0.093438 0.093671 1222400 0.0 0.0
4 1962-01-08 00:00:00-05:00 0.0 0.094370 0.092273 0.093438 1388800 0.0 0.0

Using Webscraping to Extract Exxon Revenue Data.

In [5]:
url= "https://www.macrotrends.net/stocks/charts/XOM/exxon-mobil/revenue"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
    soup = BeautifulSoup(response.content, "html.parser")
In [6]:
    table = soup.find("table", {"class": "historical_data_table"})
    
    exxon_revenue = pd.read_html(StringIO(str(table)), flavor='bs4')[0]
    
    exxon_revenue.rename(columns={
        "Exxon Annual Revenue (Millions of US $)": "Year",
        "Exxon Annual Revenue (Millions of US $).1": "Revenue"
    }, inplace=True)
    
    exxon_revenue["Revenue"] = exxon_revenue["Revenue"].str.replace(",", "").str.replace("$", "").astype(float)
    
    
    print(exxon_revenue.head())
   Year   Revenue
0  2023  344582.0
1  2022  413680.0
2  2021  285640.0
3  2020  181502.0
4  2019  264938.0
In [7]:
exxon_revenue.dropna(inplace=True)
exxon_revenue
Out[7]:
Year Revenue
0 2023 344582.0
1 2022 413680.0
2 2021 285640.0
3 2020 181502.0
4 2019 264938.0
5 2018 290212.0
6 2017 244363.0
7 2016 208114.0
8 2015 249248.0
9 2014 411939.0
10 2013 438255.0
11 2012 480681.0
12 2011 486429.0
13 2010 383221.0
14 2009 310586.0

Using yfinance to Extract Chevron Stock Data.

In [8]:
chevron = yf.Ticker("CVX")

chevron_data = chevron.history(period="max")

chevron_data.reset_index(inplace=True)
print(chevron_data.head())
                       Date  Open      High       Low     Close  Volume  \
0 1962-01-02 00:00:00-05:00   0.0  0.332397  0.327145  0.332397  105840   
1 1962-01-03 00:00:00-05:00   0.0  0.333148  0.330146  0.331647  127680   
2 1962-01-04 00:00:00-05:00   0.0  0.331647  0.328645  0.328645   75600   
3 1962-01-05 00:00:00-05:00   0.0  0.329396  0.320392  0.320392  201600   
4 1962-01-08 00:00:00-05:00   0.0  0.321893  0.316640  0.318891  126000   

   Dividends  Stock Splits  
0        0.0           0.0  
1        0.0           0.0  
2        0.0           0.0  
3        0.0           0.0  
4        0.0           0.0  

Using Webscraping to Extract Chevron Revenue Data.

In [9]:
url = "https://www.macrotrends.net/stocks/charts/CVX/chevron/revenue"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}

response = requests.get(url, headers=headers)
if response.status_code == 200:
    soup = BeautifulSoup(response.content, "html.parser")
In [10]:
    table = soup.find("table", {"class": "historical_data_table"})

    chevron_revenue = pd.read_html(StringIO(str(table)), flavor='bs4')[0]
    
    chevron_revenue.rename(columns={
        "Chevron Annual Revenue (Millions of US $)": "Year",
        "Chevron Annual Revenue (Millions of US $).1": "Revenue"
    }, inplace=True)
    
    chevron_revenue["Revenue"] = chevron_revenue["Revenue"].str.replace(",", "").str.replace("$", "").astype(float)
    
    print(chevron_revenue.head())
   Year   Revenue
0  2023  200949.0
1  2022  246252.0
2  2021  162465.0
3  2020   94692.0
4  2019  146516.0
In [11]:
chevron_revenue.dropna(inplace=True)
chevron_revenue
Out[11]:
Year Revenue
0 2023 200949.0
1 2022 246252.0
2 2021 162465.0
3 2020 94692.0
4 2019 146516.0
5 2018 166339.0
6 2017 141722.0
7 2016 114472.0
8 2015 138477.0
9 2014 211970.0
10 2013 228848.0
11 2012 241909.0
12 2011 253706.0
13 2010 204928.0
14 2009 171636.0

Plotting Exxon Stock Graph.

In [12]:
make_graph(exxon_data, exxon_revenue, 'Exxon Stock Data Graph')

Plotting Chevron Stock Graph.

In [13]:
make_graph(chevron_data, chevron_revenue, 'Chevron Stock Data Graph')

Exxon Candlestick Chart (January 2024 to May 2024).

In [14]:
exxon_data_2024 = exxon_data[(exxon_data['Date'] >= '2024-01-01') & (exxon_data['Date'] <= '2024-05-31')].copy()

exxon_data_2024.loc[:, 'Date'] = pd.to_datetime(exxon_data_2024['Date'])

fig = go.Figure(data=[go.Candlestick(x=exxon_data_2024['Date'],
                                     open=exxon_data_2024['Open'],
                                     high=exxon_data_2024['High'],
                                     low=exxon_data_2024['Low'],
                                     close=exxon_data_2024['Close'])])

fig.update_layout(title='Exxon Candlestick Chart (January 2024 to May 2024)',
                  xaxis_title='Date',
                  yaxis_title='Price',
                  xaxis_rangeslider_visible=True,
                  width=1500,  
                  height=1100)  

fig.show()

Chevron Candlestick Chart (January 2024 to May 2024).

In [15]:
chevron_data_2024 = chevron_data[(chevron_data['Date'] >= '2024-01-01') & (chevron_data['Date'] <= '2024-05-31')].copy()

chevron_data_2024.loc[:, 'Date'] = pd.to_datetime(chevron_data_2024['Date'])

fig = go.Figure(data=[go.Candlestick(x=chevron_data_2024['Date'],
                                     open=chevron_data_2024['Open'],
                                     high=chevron_data_2024['High'],
                                     low=chevron_data_2024['Low'],
                                     close=chevron_data_2024['Close'])])

fig.update_layout(title='Chevron Candlestick Chart (January 2024 to May 2024)',
                  xaxis_title='Date',
                  yaxis_title='Price',
                  xaxis_rangeslider_visible=True,
                  width=1500,  
                  height=1100)  

fig.show()
In [16]:
exxon_data_2024 = exxon_data[(exxon_data['Date'] >= '2024-01-01') & (exxon_data['Date'] <= '2024-05-31')].copy()
exxon_data_2024.loc[:, 'Date'] = pd.to_datetime(exxon_data_2024['Date'])

chevron_data_2024 = chevron_data[(chevron_data['Date'] >= '2024-01-01') & (chevron_data['Date'] <= '2024-05-31')].copy()
chevron_data_2024.loc[:, 'Date'] = pd.to_datetime(chevron_data_2024['Date'])

fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1,
                    subplot_titles=('Exxon Candlestick (January 2024 to May 2024)', 'Chevron Candlestick (January 2024 to May 2024)'))

fig.add_trace(go.Candlestick(x=exxon_data_2024['Date'],
                             open=exxon_data_2024['Open'],
                             high=exxon_data_2024['High'],
                             low=exxon_data_2024['Low'],
                             close=exxon_data_2024['Close'],
                             name='Exxon'),
              row=1, col=1)

fig.add_trace(go.Candlestick(x=chevron_data_2024['Date'],
                             open=chevron_data_2024['Open'],
                             high=chevron_data_2024['High'],
                             low=chevron_data_2024['Low'],
                             close=chevron_data_2024['Close'],
                             name='Chevron'),
              row=2, col=1)

fig.update_layout(title='Exxon vs Chevron Candlestick Charts (January 2024 to May 2024)',
                  xaxis_title='Date',
                  yaxis_title='Price',
                  xaxis_rangeslider_visible=False,
                  xaxis2_rangeslider_visible=False,
                  width=1500,  
                  height=1100)

fig.show()
In [17]:
exxon_data_2024 = exxon_data[(exxon_data['Date'] >= '2024-01-01') & (exxon_data['Date'] <= '2024-05-31')].copy()
exxon_data_2024.loc[:, 'Date'] = pd.to_datetime(exxon_data_2024['Date'])

chevron_data_2024 = chevron_data[(chevron_data['Date'] >= '2024-01-01') & (chevron_data['Date'] <= '2024-05-31')].copy()
chevron_data_2024.loc[:, 'Date'] = pd.to_datetime(chevron_data_2024['Date'])


exxon_data_2024['Daily Return'] = exxon_data_2024['Close'].pct_change()
chevron_data_2024['Daily Return'] = chevron_data_2024['Close'].pct_change()


exxon_data_2024['Cumulative Return'] = (1 + exxon_data_2024['Daily Return']).cumprod() - 1
chevron_data_2024['Cumulative Return'] = (1 + chevron_data_2024['Daily Return']).cumprod() - 1


fig = go.Figure()

fig.add_trace(go.Scatter(x=exxon_data_2024['Date'], 
                         y=exxon_data_2024['Cumulative Return'], 
                         mode='lines', 
                         name='Exxon Cumulative Return'))

fig.add_trace(go.Scatter(x=chevron_data_2024['Date'], 
                         y=chevron_data_2024['Cumulative Return'], 
                         mode='lines', 
                         name='Chevron Cumulative Return'))

fig.update_layout(title='Exxon vs Chevron Cumulative Returns (January 2024 to May 2024)',
                  xaxis_title='Date',
                  yaxis_title='Cumulative Return',
                  width=1500,
                  height=800)

fig.show()
In [18]:
fig = make_subplots(rows=1, cols=2, subplot_titles=('Exxon Closing Prices', 'Chevron Closing Prices'))

fig.add_trace(go.Box(y=exxon_data['Close'], name='Exxon'), row=1, col=1)
fig.add_trace(go.Box(y=chevron_data['Close'], name='Chevron'), row=1, col=2)

fig.update_layout(title='Box Plot of Closing Prices for Exxon and Chevron',
                  xaxis_title='',
                  yaxis_title='Price',
                  width=1000,
                  height=500)

fig.update_xaxes(title_text="Stock", row=1, col=1)
fig.update_xaxes(title_text="Stock", row=1, col=2)

fig.update_yaxes(title_text="Price", row=1, col=1)
fig.update_yaxes(title_text="Price", row=1, col=2)

fig.show()
In [19]:
exxon_data_2024 = exxon_data.loc[(exxon_data['Date'] >= '2024-01-01') & (exxon_data['Date'] <= '2024-05-31')].copy()
chevron_data_2024 = chevron_data.loc[(chevron_data['Date'] >= '2024-01-01') & (chevron_data['Date'] <= '2024-05-31')].copy()

exxon_data_2024.loc[:, 'Cumulative Volume'] = exxon_data_2024['Volume'].cumsum()
chevron_data_2024.loc[:, 'Cumulative Volume'] = chevron_data_2024['Volume'].cumsum()

fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
                    subplot_titles=('Cumulative Trading Volume (Exxon vs Chevron)',
                                    'Stacked Daily Trading Volume (Exxon vs Chevron)'))

fig.add_trace(go.Scatter(x=exxon_data_2024['Date'], y=exxon_data_2024['Cumulative Volume'], mode='lines', name='Exxon'),
              row=1, col=1)
fig.add_trace(go.Scatter(x=chevron_data_2024['Date'], y=chevron_data_2024['Cumulative Volume'], mode='lines', name='Chevron'),
              row=1, col=1)

fig.add_trace(go.Bar(x=exxon_data_2024['Date'], y=exxon_data_2024['Volume'], name='Exxon', marker_color='blue'),
              row=2, col=1)
fig.add_trace(go.Bar(x=chevron_data_2024['Date'], y=chevron_data_2024['Volume'], name='Chevron', marker_color='orange'),
              row=2, col=1)

fig.update_layout(title='Trading Volume Comparison: Exxon vs Chevron',
                  xaxis_title='Date',
                  yaxis_title='Volume',
                  showlegend=True,
                  width=1500,
                  height=1000)

fig.update_xaxes(title_text="Date", row=1, col=1)
fig.update_xaxes(title_text="Date", row=2, col=1)

fig.update_yaxes(title_text="Cumulative Volume", row=1, col=1)
fig.update_yaxes(title_text="Daily Volume", row=2, col=1)

fig.show()
In [ ]: